package com.github.nacosone.core;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;
/**
 * <a href="https://juejin.cn/post/6976980590415314958">Mybatis-Plus通用CRUD封装</a>
 */

public abstract class AbstractCoreController <T> {

    private final IService<T> coreService;

    public AbstractCoreController(IService<T> coreService) {
        this.coreService = coreService;
    }

    /**
     * 删除记录
     */
    @ApiOperation(value = "删除")
    @DeleteMapping("/{id}")
    public Result<T> deleteById(@PathVariable(name = "id") Serializable id) {

        boolean flag = coreService.removeById(id);
        if (!flag) {
            return Result.error();
        }
        return Result.ok();
    }

    /**
     * 添加记录
     */
    @ApiOperation(value = "添加")
    @PostMapping
    public Result<T> insert(@RequestBody T record) {
        boolean flag = coreService.save(record);
        if (!flag) {
            return Result.error();
        }
        return Result.ok(record);
    }

    /**
     * 更新数据
     */
    @ApiOperation(value = "更新")
    @PutMapping
    public Result<T> updateByPrimaryKey(@RequestBody T record) {
        boolean flag = coreService.updateById(record);
        if (!flag) {
            return Result.error();
        }
        return Result.ok();
    }

    /**
     * 查询数据
     */
    @ApiOperation(value = "查询")
    @GetMapping("/{id}")
    public Result<T> findById(@PathVariable(name = "id") Serializable id) {
        T t = coreService.getById(id);
        return Result.ok(t);
    }

    /**
     * 查询所有数据
     */
    @ApiOperation(value = "查询所有")
    @GetMapping
    public Result<List<T>> findAll() {
        List<T> list = coreService.list();
        return Result.ok(list);
    }

    /**
     * 通用条件分页查询
     * @param pageRequestDto 通用条件
     */
    @ApiOperation(value = "分页条件")
    @PostMapping(value = "/search")
    public Result<PageInfo<T>> findByPage(@RequestBody PageRequestDto<T> pageRequestDto) {

        //构造分页条件
        IPage<T> page = new Page<T>(pageRequestDto.getPage(), pageRequestDto.getSize());

        //条件查询 非 lamda表达式查询条件
        QueryWrapper<T> queryWrapper = getWrapper(pageRequestDto.getBody());

        //分页查询
        IPage<T> iPage = coreService.page(page, queryWrapper);

        //封装返回数据
        PageInfo<T> pageInfo = new PageInfo<>(iPage.getCurrent(), iPage.getSize(), iPage.getTotal(), iPage.getPages(), iPage.getRecords());
        return Result.ok(pageInfo);
    }

    /**
     * 根据body参数构建查询条件
     * @param body 查询参数
     */
    private QueryWrapper<T> getWrapper(T body) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<T>();

        if (body == null) {
            return queryWrapper;
        }

        Field[] declaredFields = body.getClass().getDeclaredFields();
        for (Field declaredField : declaredFields) {
            try {
                //遇到 id注解 则直接跳过 不允许实现根据主键查询
                //https://www.coder.work/article/2808807
                if (declaredField.isAnnotationPresent(TableId.class) || "serialVersionUID".equals(declaredField.getName())) {
                    // 遇到 id
                    continue;
                }
                //属性描述器  record.getClass()
                PropertyDescriptor propDesc = new PropertyDescriptor(declaredField.getName(), body.getClass());
                //获取这个值  先获取读方法的方法对象,并调用获取里面的值
                Object value = propDesc.getReadMethod().invoke(body);
                //查询变量的 @TableField 注解）
                TableField annotation = declaredField.getAnnotation(TableField.class);
                //如果传递的值为空则不做处理
                if (value != null && annotation != null) {
                    //如是字符串 则用like
                    if ("java.lang.String".equals(value.getClass().getName())) {
                        queryWrapper.like(annotation.value(), value);
                    } else {
                        //否则使用=号
                        queryWrapper.eq(annotation.value(), value);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return queryWrapper;
    }
}
